<?php

namespace app\api\controller\v2;

use app\admin\model\Score as ScoreModel;

use think\Db;
use think\Exception;

/**
 * 积分变动
 * 只能进行方法间的调用,禁止api请求访问
 */
class Score
{


    /**
     * 调整积分
     * @param $user_id 用户id
     * @param $ref_sn_id 关联id 0:没有
     * @param $config_name config配置表中积分的name字段的值
     * @param $seq_flag 1:增加积分,2:减少积分
     * @param $table_name 关联id的来源不带前缀的表名 评论点赞转发的存的是内容的id的表名如plate_post video之类的,不会存评论点赞的表名 null:没有
     * @throws Exception 积分配置不正确
     */
    public function editScore($user_id, $ref_sn_id, $config_name, $seq_flag, $table_name)
    {

        $res = [
            'code' => 200,
            'msg' => '更新成功'
        ];
        $config = \app\common\model\Config::where('group', 'score_config')
            ->where('name', $config_name)
            ->field('id,name,title,tip,value')
            ->find();
        if ($config) {
            $score = $config['value'];//积分
            $memo = $config['tip'];//备注

            switch ($config['name']) {
                case 'register_score':
                    $change_type = 1;//注册
                    break;
                case 'input_post_score':
                    $change_type = 2;//发帖
                    break;
                case 'comment_score':
                    $change_type = 3;//评论
                    break;
                case 'repost_score':
                    $change_type = 4;//转发
                    break;
                case 'favorite_score':
                    $change_type = 5;//收藏
                    break;
                case 'highlight_score':
                    $change_type = 6;//加精
                    break;
                case 'top_score':
                    $change_type = 7;//置顶
                    break;
                case 'by_favorite_score':
                    $change_type = 8;//被收藏
                    break;
                case 'by_repost_score':
                    $change_type = 9;//被转发
                    break;
                case 'attachment_download_score':
                    $change_type = 10;//下载附件
                    break;
                case 'watch_video_score':
                    $change_type = 11;//观看视频
                    break;
                case 'invite_register':
                    $change_type = 14;//使用邀请码注册增加积分(给邀请码的主人增加积分)
                    break;
                default:
                    $res['code'] = 500;
                    $res['msg'] = '积分变量名称不正确';
            }

            if ($res['code'] == 500) {
                return $res;
            }

            //增加积分且change_type!=下载附件
            if ($seq_flag == 1 && $change_type != 10) {
                $isCompliantAdd = $this->isCompliantAdd($change_type, $user_id, $ref_sn_id);
                if (!$isCompliantAdd['success']) {
                    $res['code'] = 500;
                    $res['msg'] = '积分表不符合规则';
                    return $res;
                }

                if ($isCompliantAdd['score_add_num'] > 0) {
                    $score = $isCompliantAdd['score_add_num'];
                }
            }

            Db::startTrans();
            try {
                $user = \app\admin\model\User::lock(true)->find($user_id);
                if ($user && $score != 0) {
                    //1=增加积分,2=减少积分
                    if ($seq_flag == 1) {
                        $after = $user->score + $score;//现在的积分
                        $comments = $table_name . '|' . $memo . '+' . $score;
                        //更新积分
                        ScoreModel::create([
                            'user_id' => $user['id'],
                            'change_type' => $change_type,//变动类型:1=注册,2=发帖,3=评论,4=转发,5=收藏,6=加精,7=置顶,8=被收藏,9=被转发,10=下载附件,11=观看视频,12=积分消费(购买会员、分类、内容之类的)'
                            'change_num' => $score,//变动数量
                            'seq_flag' => 1,//变动方向:1=增加,2=减少
                            'change_time' => time(),//变动时间
                            'ref_sn' => $ref_sn_id,//关联ID
                            'table_name' => $table_name,//备注
                            'comments' => $comments,//备注
                            'show_notes' => $memo . '+' . $score,//显示说明
                        ]);
                    } else {
                        //判断是否是因为下载附件扣除积分
                        if ($change_type == 10) {
                            //下载附件扣除积分
                            $after = $user->score - $score;//现在的积分
                            $comments = $table_name . '|' . $memo . '-' . $score;
                            ScoreModel::create([
                                'user_id' => $user['id'],
                                'change_type' => $change_type,//变动类型:1=注册,2=发帖,3=评论,4=转发,5=收藏,6=加精,7=置顶,8=被收藏,9=被转发,10=下载附件,11=观看视频'
                                'change_num' => $score,//变动数量
                                'seq_flag' => 1,//变动方向:1=增加,2=减少
                                'change_time' => time(),//变动时间
                                'ref_sn' => $ref_sn_id,//关联ID
                                'table_name' => $table_name,//备注
                                'comments' => $comments,//备注
                                'show_notes' => $memo . '+' . $score,//显示说明
                            ]);
                        }else{
                            //因为是直接删除积分的数据行,则需要先得到之前系统给了多少积分,然后在进行运算
                            $score = ScoreModel::where('user_id',$user['id'])->where('change_type',$change_type)->where('seq_flag',1)->where('ref_sn',$ref_sn_id)->value('change_num') ?? 0;
                            $after = $user->score - $score;//现在的积分
                            ScoreModel::where('user_id',$user['id'])
                                ->where('change_type',$change_type)
                                ->where('seq_flag',1)
                                ->where('ref_sn',$ref_sn_id)
                                ->delete();
                        }
                    }

                    $level = $this->nextlevel($after);
                    //更新会员信息
                    $user->save(['score' => $after, 'level' => $level]);

                }
                Db::commit();
            } catch (Exception $e) {
                Db::rollback();
                $res['code'] = 500;
                $res['msg'] = '错误原因' . $e->getMessage();
            }
        } else {
            $res['code'] = 500;
            $res['msg'] = '积分配置不正确';
        }
        return $res;
    }

    /**
     * 是否符合变动规则
     * @param $change_type 变动类型:1=注册,2=发帖,3=评论,4=转发,5=收藏,6=加精,7=置顶,8=被收藏,9=被转发,10=下载附件',
     * @return mixed
     */
    private function isCompliantAdd($change_type, $user_id, $ref_sn_id)
    {
        $today_start_time = strtotime('today');//输出当天 0:00:00 对应的时间戳
        $today_end_time = strtotime('today 23:59:59');// 输出当天 23:59:59 对应的时间戳

        $res = [
            'success' => true,//通过
            'score_add_num' => 0//积分增加了多少分
        ];
        $score = ScoreModel::where('user_id', $user_id)
            ->where('seq_flag', 1);
        switch ($change_type) {
            case 1://注册,只能给1次积分
                $count = $score->where('change_type', $change_type)->count();
                if ($count >= 1) {
                    $res['success'] = false;
                }
                break;
            case 2:
                //发帖,不限制,无需判断
                $count = $score->where('change_type', $change_type)->where('ref_sn', $ref_sn_id)->count();
                if ($count >= 1) {
                    $res['success'] = false;
                }
                break;
            case in_array($change_type, [3, 4, 5, 11])://评论,转发,收藏,每日每项最多5分 观看视频得分+5
                $sum = $score->where('change_type', $change_type)
                        ->where('seq_flag', 1)
                        ->whereBetween('change_time', [$today_start_time, $today_end_time])
                        ->sum('change_num') ?? 0;
                if ($change_type == 3){//评论
                    $name = 'comment_score';
                } elseif ($change_type == 4) {//转发
                    $name = 'repost_score';
                } elseif ($change_type == 5) {//收藏
                    $name = 'favorite_score';
                } elseif ($change_type == 11) {//观看视频
                    $name = 'daily_watch_video_limit';
                }

                //获取每日最多得分上限
                $max_score = \app\common\model\Config::where('name',$name)->value('value') ?? 0;
                if ($sum >= $max_score) {
                    $res['success'] = false;
                }
                break;
            case in_array($change_type, [6, 7])://加精+50,置顶+50 每篇帖子这4项目总和最多100分,一次性
                $count = $score->where('change_type', $change_type)->where('ref_sn', $ref_sn_id)->count();
                if ($count >= 1) {
                    $res['success'] = false;
                } else {
                    $sum = $score->whereIn('change_type', [6, 7, 8, 9])->where('ref_sn', $ref_sn_id)->sum('change_num') ?? 0;

                    $score_add_num = 100 - ($sum + 50);

                    if ($score_add_num < 0) {
                        $res['success'] = false;
                    } else {
                        $res['score_add_num'] = 50 - abs($score_add_num);
                    }
                }
                break;
            case in_array($change_type, [8, 9])://被收藏、被转发各2分,每篇帖子这4项目总和最多100分,一次性
                $sum = $score->whereIn('change_type', [6, 7, 8, 9])->where('ref_sn', $ref_sn_id)->sum('change_num') ?? 0;
                $score_add_num = 100 - ($sum + 2);
                if ($score_add_num < 0) {
                    $res['success'] = false;
                } else {
                    $res['score_add_num'] = 2 - abs($score_add_num);
                }
                break;
            case 14://使用邀请码注册给邀请码的主人加积分,不设置拉新的上限
                $count = $score->where('change_type', $change_type)->where('ref_sn', $ref_sn_id)->count();
                $res['success'] = true;
                break;
        }
        return $res;
    }

    //计算用户等级
    private function nextlevel($score = 0)
    {
        $lv = array(1 => 0, 2 => 30, 3 => 100, 4 => 500, 5 => 1000, 6 => 2000, 7 => 3000, 8 => 5000, 9 => 8000, 10 => 10000);
        $level = 1;
        foreach ($lv as $key => $value) {
            if ($score >= $value) {
                $level = $key;
            }
        }
        return $level;
    }


}
